package com.ybear.mvp.view;

import android.app.Activity;
import android.app.Fragment;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.os.Message;
import android.os.PersistableBundle;
import android.util.Printer;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.util.Consumer;
import androidx.viewbinding.ViewBinding;

import com.ybear.mvp.BaseVP;
import com.ybear.mvp.ICallArguments;
import com.ybear.mvp.ViewLife;
import com.ybear.mvp.annotations.Model;
import com.ybear.mvp.handler.DelegateHandler;
import com.ybear.mvp.handler.Handler;
import com.ybear.mvp.handler.HandlerCallback;
import com.ybear.mvp.util.MvpAnn;
import com.ybear.mvp.view.bind.BindHelper;
import com.ybear.mvp.view.bind.IViewBindSelf;

import java.util.concurrent.Callable;

public abstract class MvpActivity<VB extends ViewBinding> extends Activity implements BaseVP,
        IViewBindSelf<VB>, IViewSelf<MvpActivity<VB>>, Handler, HandlerCallback, ICallArguments {
    @Model
    private ViewLife<BaseVP> mLife;
    private final DelegateHandler mHandler = DelegateHandler.create( this );
    private final BindHelper<VB> mBind = new BindHelper<>( this );

    public MvpActivity() {
        super();
        //实例被Model注解的成员变量
        MvpAnn.instanceMvpAnn( this );
    }

    @Override
    public void setContentView(View view) {
        super.setContentView(view);
        //实例当前注解BindView的成员变量
        MvpAnn.instanceBindAll( this );
    }
    @Override
    public void setContentView(int layoutResId) {
        super.setContentView( layoutResId );
        //实例当前注解BindView的成员变量
        MvpAnn.instanceBindAll( this );
    }
    @Override
    public void setContentView(View view, ViewGroup.LayoutParams params) {
        super.setContentView(view, params);
        //实例当前注解BindView的成员变量
        MvpAnn.instanceBindAll( this );
    }

    @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        mLife.onNewIntent( this, intent );
    }

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mBind.bindView( this, getLayoutInflater(), null );
        mLife.onCreate( this, savedInstanceState );
    }

    @Override
    protected void onStart() {
        super.onStart();
        mLife.onStart( this );
    }

    @Override
    protected void onRestart() {
        super.onRestart();
        mLife.onReStart( this );
    }


    @Override
    protected void onResume() {
        super.onResume();
        mLife.onResume( this );
    }

    @Override
    protected void onPause() {
        super.onPause();
        mLife.onPause( this );
    }

    @Override
    protected void onStop() {
        super.onStop();
        mLife.onStop( this );
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        mLife.onDestroy( this );
        mBind.onDestroyView();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
                                           @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        mLife.onRequestPermissionsResult( this, requestCode, permissions, grantResults );
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        mLife.onActivityResult( this, requestCode, resultCode, data );
    }

    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        mLife.onSaveInstanceState( this, outState );
    }

    @Override
    public void onSaveInstanceState(@NonNull Bundle outState,
                                    @NonNull PersistableBundle outPersistentState) {
        super.onSaveInstanceState(outState, outPersistentState);
        mLife.onSaveInstanceState( this, outState, outPersistentState );
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return mLife.onTouchEvent( this, super.onTouchEvent( ev ), ev );
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        return mLife.dispatchTouchEvent( this, super.dispatchTouchEvent( ev ), ev );
    }

    @Override
    public boolean dispatchKeyEvent(KeyEvent ev) {
        return mLife.dispatchKeyEvent( this, super.dispatchKeyEvent( ev ), ev );
    }

    @Override
    public boolean dispatchKeyShortcutEvent(KeyEvent ev) {
        return mLife.dispatchKeyShortcutEvent( this, super.dispatchKeyShortcutEvent( ev ), ev );
    }

    @Override
    public boolean dispatchTrackballEvent(MotionEvent ev) {
        return mLife.dispatchTrackballEvent( this, super.dispatchTrackballEvent( ev ), ev );
    }

    @Override
    public boolean dispatchGenericMotionEvent(MotionEvent ev) {
        return mLife.dispatchGenericMotionEvent( this, super.dispatchGenericMotionEvent( ev ), ev );
    }

    @Override
    public MvpActivity<VB> getThis() { return this; }

    @NonNull
    @Override
    public VB getViewBinding() { return mBind.getViewBinding(); }

    @Nullable
    public final Context getContext() { return mLife.getContext( this ); }

    @Nullable
    public final Activity getActivity() { return mLife.getActivity( this ); }

    @Nullable
    public Fragment findFragmentById( int id ) {
        return getFragmentManager().findFragmentById(  id );
    }

    /**
     * Fragment处接收的参数
     * @param args      参数
     */
    @Override
    public void onCallArguments(@Nullable Bundle args) { }

    /**
     * 监听view(Activity)的生命周期状态
     * V层的活动状态发生改变时会调用该接口，这样P层就可以实时知道V层的状态。
     * @param status    活动状态
     */
    @Override
    public void onLifeStatus(int status, @Nullable Bundle b) { }

    /**
     * 获取当前Activity 或者 Fragment 的当前生命周期状态
     * @return  {@link com.ybear.mvp.annotations.LifeStatus}
     */
    @Override
    public int getLifeStatus() { return mLife.getLifeStatus(); }

    /* Handler */
    @NonNull
    @Override
    public android.os.Handler getOsHandler() { return mHandler.getOsHandler(); }
    @NonNull
    @Override
    public final Handler getHandler() { return mHandler.getHandler(); }
    @Override
    public boolean post(Runnable r) { return getHandler().post( r ); }
    @Override
    public boolean post(Runnable r, long delayMillis) {
        return getHandler().postDelayed( r, delayMillis );
    }
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public boolean post(Runnable r, @Nullable Object token, long delayMillis) {
        return getHandler().postDelayed( r, token, delayMillis );
    }
    @Override
    public boolean postDelayed(Runnable r, long delayMillis) {
        return getHandler().postDelayed( r, delayMillis );
    }
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public boolean postDelayed(@NonNull Runnable r, @Nullable Object token, long delayMillis) {
        return getHandler().postDelayed( r, token, delayMillis );
    }
    @Override
    public boolean postAtFrontOfQueue(@NonNull Runnable r) {
        return getHandler().postAtFrontOfQueue( r );
    }
    @Override
    public boolean postAtTime(@NonNull Runnable r, long uptimeMillis) {
        return getHandler().postAtTime( r, uptimeMillis );
    }
    @Override
    public boolean postAtTime(@NonNull Runnable r, @Nullable Object token, long uptimeMillis) {
        return getHandler().postAtTime( r, token, uptimeMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult) {
        return getHandler().postAsync( executeCall, resultCall, postResult );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult) {
        return getHandler().postAsync( executeCall, resultCall, postResult );
    }

    @Override
    public <T> boolean postDelayedAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return getHandler().postDelayedAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postDelayedAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return getHandler().postDelayedAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return getHandler().postAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, boolean postResult, long delayMillis) {
        return getHandler().postAsync( executeCall, resultCall, postResult, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall) {
        return getHandler().postAsync( executeCall, resultCall );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall) {
        return getHandler().postAsync( executeCall, resultCall );
    }

    @Override
    public <T> boolean postDelayedAsync(Callable<T> executeCall, Consumer<T> resultCall, long delayMillis) {
        return getHandler().postDelayedAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postDelayedAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, long delayMillis) {
        return getHandler().postDelayedAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Callable<T> executeCall, Consumer<T> resultCall, long delayMillis) {
        return getHandler().postAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Consumer<Consumer<T>> executeCall, Consumer<T> resultCall, long delayMillis) {
        return getHandler().postAsync( executeCall, resultCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Runnable executeCall) {
        return getHandler().postAsync( executeCall );
    }

    @Override
    public <T> boolean postDelayedAsync(Runnable executeCall, long delayMillis) {
        return getHandler().postDelayedAsync( executeCall, delayMillis );
    }

    @Override
    public <T> boolean postAsync(Runnable executeCall, long delayMillis) {
        return getHandler().postAsync( executeCall, delayMillis );
    }

    @Override
    public boolean sendMessage(@NonNull Message msg) { return getHandler().sendMessage( msg ); }
    @Override
    public boolean sendEmptyMessage(int what) { return getHandler().sendEmptyMessage( what ); }
    @Override
    public boolean sendEmptyMessageDelayed(int what, long delayMillis) {
        return getHandler().sendEmptyMessageDelayed( what, delayMillis );
    }
    @Override
    public boolean sendEmptyMessageAtTime(int what, long uptimeMillis) {
        return getHandler().sendEmptyMessageAtTime( what, uptimeMillis );
    }
    @Override
    public boolean sendMessageDelayed(@NonNull Message msg, long delayMillis) {
        return getHandler().sendMessageDelayed( msg, delayMillis );
    }
    @Override
    public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) {
        return getHandler().sendMessageAtTime( msg, uptimeMillis );
    }
    @Override
    public boolean sendMessageAtFrontOfQueue(@NonNull Message msg) {
        return getHandler().sendMessageAtFrontOfQueue( msg );
    }

    @Override
    public boolean hasMessages(int what) { return getHandler().hasMessages( what ); }
    @Override
    public boolean hasMessages(int what, @Nullable Object object) {
        return getHandler().hasMessages( what, object );
    }

    @Override
    public void removeMessages(int what) {
        getHandler().removeMessages( what );
    }
    @Override
    public void removeMessages(int what, @Nullable Object object) {
        getHandler().removeMessages( what, object );
    }

    @RequiresApi(api = Build.VERSION_CODES.Q)
    @Override
    public boolean hasCallbacks(@NonNull Runnable r) { return getHandler().hasCallbacks( r ); }

    @Override
    public void removeCallbacks(@NonNull Runnable r) { getHandler().removeCallbacks( r ); }
    @Override
    public void removeCallbacks(@NonNull Runnable r, @Nullable Object token) {
        getHandler().removeCallbacks( r, token );
    }

    @Override
    public void removeCallbacksAndMessages(@Nullable Object token) {
        getHandler().removeCallbacksAndMessages( token );
    }

    @NonNull
    @Override
    public Message obtainMessage() { return getHandler().obtainMessage(); }
    @NonNull
    @Override
    public Message obtainMessage(int what) { return getHandler().obtainMessage( what ); }
    @NonNull
    @Override
    public Message obtainMessage(int what, @Nullable Object obj) {
        return getHandler().obtainMessage( what, obj );
    }
    @NonNull
    @Override
    public Message obtainMessage(int what, int arg1, int arg2) {
        return getHandler().obtainMessage( what, arg1, arg2 );
    }
    @NonNull
    @Override
    public Message obtainMessage(int what, int arg1, int arg2, @Nullable Object obj) {
        return getHandler().obtainMessage( what, arg1, arg2, obj );
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public android.os.Handler createAsyncForOs(@NonNull Looper looper) {
        return android.os.Handler.createAsync( looper );
    }
    @RequiresApi(api = Build.VERSION_CODES.P)
    @Override
    public android.os.Handler createAsyncForOs(@NonNull Looper looper,
                                               @NonNull android.os.Handler.Callback callback) {
        return android.os.Handler.createAsync( looper, callback );
    }

    @Override
    public void dump(@NonNull Printer pw, @NonNull String prefix) { getHandler().dump( pw, prefix ); }

    @NonNull
    @Override
    public Looper getLooper() { return getHandler().getLooper(); }

    @Override
    public boolean handleMessage(@NonNull Message msg) {
        mLife.handleMessageToFragments( this, msg );
        return false;
    }
    @Override
    public void dispatchMessage(@NonNull Message msg) {
        mLife.dispatchMessageToFragments( this, msg );
    }
}